package com.shareware.common

import android.annotation.SuppressLint
import android.app.Application
import android.content.Context
import android.os.Build
import android.webkit.WebView
import com.shareware.common.exception.CrashException
import com.shareware.common.model.FontType
import com.shareware.common.utils.*
import com.tencent.mars.xlog.Log
import com.tencent.mars.xlog.Xlog
import io.reactivex.plugins.RxJavaPlugins
import java.io.File
import java.io.RandomAccessFile
import java.text.SimpleDateFormat
import java.util.*
import kotlin.concurrent.thread


/**
 * desc: 功能描述
 * email: mobiledeveloper@qq.com
 */

//全局的context
@SuppressLint("StaticFieldLeak")
private var contextGlobal: Context? = null

/**
 * 是否是debug模式
 */
var debugGlobal: Boolean = false
    private set

/**
 * 获取上下文
 * @return 上下文
 */
fun getContextGlobal(): Context {
    return contextGlobal ?: throw RuntimeException("install first")
}

/**
 * 初始化
 * application onCreate时触发
 * @param context 上下文
 */
fun install(context: Application) {
    if (contextGlobal != null) {
        return
    }
    contextGlobal = context.applicationContext
    CrashException.start()
    hookWebViewMultiProcess()
    context.registerActivityLifecycleCallbacks(ActivityExt.lifecycleCallbacks)
    setAppFontMode(FontType.STANDARD)
    NetConnectService.register()
    RxJavaPlugins.setErrorHandler {
        trackError(it)
        logStackTrace(DEFAULT, it)
    }
}

var appFontScale = 1.1f
    private set

fun setAppFontMode(mode: FontType) {
    appFontScale = when (mode) {
        FontType.SMALL -> {
            1.0f
        }

        FontType.LARGE -> {
            1.3f
        }

        else -> {
            1.1f
        }
    }
    getContextGlobal().resources.displayMetrics.scaledDensity =
        getContextGlobal().resources.displayMetrics.density * appFontScale
}

/**
 * 前后台监听必须在application trimMemory方法实现
 * @param level 等级
 */
fun trimMemory(level: Int) {
    if (level == android.content.ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) {
        appBackground = true
    }
}

/**
 * 设置debug模式
 * @param logTime 日志存储时长
 */
@JvmOverloads
fun setDebugGlobal(
    consoleOpen: Boolean,
    logTime: Int = 7,
    logRoot: String = "",
    pubKey: String = "",
    logNamePrefix: String = "Log"
) {
    debugGlobal = true
    val processName = getCurProcessName()
    val packageName = getContextGlobal().packageName
    val fileName = if (processName == packageName) {
        thread {
            tryMethodIgnore {
                val dateFormat = SimpleDateFormat("yyyyMMdd", Locale.getDefault())
                File(getLogPath(logRoot)).createFile(false).listFiles()?.forEach {
                    if (it.name.endsWith(".xlog")) {
                        val fileDate = it.name.substring(
                            it.name.indexOf("_") + 1,
                            it.name.indexOf(".")
                        )
                        val date = dateFormat.parse(fileDate)
                        if (date != null && (System.currentTimeMillis() - date.time) > logTime * 86400000L) {
                            it.delete()
                        }
                    }
                }
            }
        }
        logNamePrefix
    } else if (processName.contains(":")) {
        "$logNamePrefix${processName.substringAfter(":")}"
    } else {
        processName
    }
    if (fileName.isNotEmpty()) {
        Xlog.open(
            true,
            Xlog.LEVEL_DEBUG,
            Xlog.AppednerModeAsync,
            "${getContextGlobal().cacheDir}/xlog",
            getLogPath(logRoot),
            fileName,
            pubKey
        )
        Log.setLogImp(Xlog())
        Xlog.setConsoleLogOpen(consoleOpen)
    }
}

/**
 * 处理极端场景多进程WebView启动的情况下，前一个进程还在锁定缓存文件目录操作，后一个进程也要加锁，才会失败
 */
private fun hookWebViewMultiProcess() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        tryMethodIgnore {//WebView9.0多进程crash问题
            val processName = getCurProcessName()
            if (processName != getContextGlobal().packageName) {
                WebView.setDataDirectorySuffix(processName)
            }
            val lockFile = "/webview_data.lock"
            val dataPath = getContextGlobal().dataDir.absolutePath
            val suffix = "_$processName"
            val pathList = arrayListOf("$dataPath/app_webview$suffix$lockFile")
            if (isHuawei()) {
                pathList.add("$dataPath/app_hws_webview$suffix$lockFile")
            }
            pathList.forEach {
                val file = File(it)
                if (file.exists()) {
                    try {
                        RandomAccessFile(file, "rw").channel.tryLock().close()
                    } catch (ignore: Exception) {
                        file.createFile(true)
                    }
                }
            }
        }
    }
}
